#include "CAEN_module.h"
#include "vme_sis.h"

// --- constructor ---
CAEN_module::CAEN_module(int handle,u_int32_t addr)
		: VmeModule(handle,addr)
{
}


u_int32_t CAEN_module::GetNChannels()
{
	// Virtual Function - has to be overwritten by descendants
	return 0;
}


u_int32_t CAEN_module::GetEventCounter()
{
		u_int16_t l,h;

		readA32D16(handle,address+EVENT_COUNTER_L,&l);
		readA32D16(handle,address+EVENT_COUNTER_H,&h);

		u_int32_t r = ((h & 0xff) << 16) | l;

//		cerr << hex << "CAEN_module::GetEventCounter(): l=0x" << l << " h=0x"<< h
//				 << " r=0x" << r << endl;

		return r;
}

									   
void CAEN_module::SetBit1Pattern(u_int16_t pattern)
{
		writeA32D16(handle,address+BITSET_1,
								pattern & BITSET_1_ALLOWED_BITS);
}


void CAEN_module::ClearBit1Pattern(u_int16_t pattern)
{
		writeA32D16(handle,address+BITCLEAR_1,
								pattern & BITSET_1_ALLOWED_BITS);
}


void CAEN_module::SetBit2Pattern(u_int16_t pattern)
{
		writeA32D16(handle,address+BITSET_2,
								pattern & BITSET_2_ALLOWED_BITS);
}


void CAEN_module::ClearBit2Pattern(u_int16_t pattern)
{
		writeA32D16(handle,address+BITCLEAR_2,
								pattern & BITSET_2_ALLOWED_BITS);
}


void CAEN_module::SoftwareReset()
{
		SetBit1Pattern(BITSET_1_SOFTWARE_RESET);
		ClearBit1Pattern(BITSET_1_SOFTWARE_RESET);
}


void CAEN_module::EnableChannel(u_int16_t ch)
{
		u_int16_t old;
		
		if (ch >= GetNChannels())
				throw IOError((string("CAEN_module::EnableChannel(): Channel ")+ch+" does not exist").c_str(),ch);

 		 readA32D16(handle,address+THRESHOLD_START+(2*ch),&old);
		writeA32D16(handle,address+THRESHOLD_START+(2*ch),
								old & THRESHOLD_MASK);
}


void CAEN_module::DisableChannel(u_int16_t ch)
{
		u_int16_t old;

		if (ch >= GetNChannels())
				throw IOError((string("CAEN_module::EnableChannel(): Channel ")+ch+" does not exist").c_str(),ch);
											  
		readA32D16(handle,address+THRESHOLD_START+(2*ch),&old);
		writeA32D16(handle,address+THRESHOLD_START+(2*ch),
								(old & THRESHOLD_MASK) | CH_DISABLE_MASK);
}


void CAEN_module::SetThreshold(u_int16_t ch, u_int16_t thr)
{
		if (ch >= GetNChannels())
				throw IOError((string("CAEN_module::SetThreshold(): Channel ")
											 +ch+" does not exist").c_str(),ch);
		
		if (thr > THRESHOLD_MASK)
				throw IOError(( string("CAEN_module::SetThreshold(): Requested threshold")
												+ thr
												+ " is larger then the maximum possible threshold."
													).c_str(), thr );
		
		u_int16_t old;
 		 readA32D16(handle,address+THRESHOLD_START+(2*ch),&old);
		writeA32D16(handle,address+THRESHOLD_START+(2*ch),
								old & THRESHOLD_MASK);
}


void CAEN_module::DefineChannelBehaviour(u_int32_t Pattern)
{
		for (u_int32_t i = 0; i < GetNChannels(); i++)
		{
				if ((1 << i) & Pattern)
						EnableChannel(i);
				else
						DisableChannel(i);
		}
}


void CAEN_module::DefineChannelBehaviour(u_int32_t Pattern, u_int16_t Threshold)
{
		for( u_int32_t i=0; i < GetNChannels(); i++ )
		{
				SetThreshold( i, Threshold);
				if ((1 << i) & Pattern)
						EnableChannel(i);
				else
						DisableChannel(i);
		}
}

void CAEN_module::CountOnlyValidEvents()
{
		ClearBit2Pattern(BITSET_2_ALL_TRIGGERS);
}


void CAEN_module::CountAllEvents()
{
		SetBit2Pattern(BITSET_2_ALL_TRIGGERS);
}


u_int16_t CAEN_module::GetFastClearWindow()
{
		u_int16_t d;

		readA32D16(handle,address+FAST_CLEAR_WINDOW_REGISTER,&d);

		return d & FAST_CLEAR_WINDOW_MASK;
}


void CAEN_module::SetFastClearWindow( u_int16_t width )
{
		if( width > FAST_CLEAR_WINDOW_MAXWIDTH)
				throw IOError((string("CAEN_module::SetFastClearWindow():"
															"width to big (")+width+")").c_str(),width);

		writeA32D16(handle,address+FAST_CLEAR_WINDOW_REGISTER,
								width & FAST_CLEAR_WINDOW_MASK);
}


void CAEN_module::ClearData()
{
		SetBit2Pattern(BITSET_2_CLEAR_DATA_BIT);
		ClearBit2Pattern(BITSET_2_CLEAR_DATA_BIT);
		ClearEventCounter();
}


void CAEN_module::ClearEventCounter()
{
		writeA32D16(handle,address + EVENT_COUNTER_RESET, 0xaffe);
}


bool CAEN_module::BufferEmpty()
{
		return ( (GetStatus2() & STATUS_REGISTER_2_BUFFER_EMPTY)
						 == STATUS_REGISTER_2_BUFFER_EMPTY);
}


bool CAEN_module::BufferFull()
{
		return ( (GetStatus2() & STATUS_REGISTER_2_BUFFER_FULL)
						 == STATUS_REGISTER_2_BUFFER_FULL);
}


u_int16_t CAEN_module::GetStatus2()
{
		u_int16_t d;

		readA32D16(handle, address + STATUS_REGISTER_2, &d);

    return d;
}


u_int16_t CAEN_module::GetStatus1()
{
		u_int16_t d;

		readA32D16(handle, address + STATUS_REGISTER_1, &d);

    return d;
}
